use colored::Colorize;

pub struct Flag<'a> {
    args: Vec<String>,
    params: Vec<Param<'a>>,
    base_path: &'a str,
    author: &'a str,
    config_path: &'a str
}

impl<'a> Flag<'a> {

    // new 解析参数
    pub fn new(args: Vec<String>) -> Self {

        let mut version_param = Param::new();
        version_param.short_name("v").param_name("version").describe("版本").default_value("1.0.0").is_interrupt(true).is_required(false);

        let mut config_param = Param::new();
        config_param.short_name("f").param_name("config").describe("配置文件").default_value("default.json");

        let mut help_param = Param::new();
        help_param.short_name("h").param_name("help").describe("帮助").is_interrupt(true).is_required(false);

        let mut path_param = Param::new();
        path_param.short_name("p").param_name("base_path").describe("路径").default_value(".").is_required(false);

        let mut author_param = Param::new();
        author_param.short_name("a").param_name("author").describe("作者").default_value("molong");


        Flag {
            args: args[1..].to_owned(),
            params: vec![version_param, help_param, config_param, path_param, author_param],
            base_path: "",
            author: "",
            config_path: ""
        }
    }

    fn banner(&self) {
        let banner: &str = r"
,--,--,--. ,---. ,-----.,--.--. ,---.,--.  ,--.,---. ,--.--. ,---.  ,---.
|        || .-. |'-----'|  .--'| .-. :\  `'  /| .-. :|  .--'(  .-' | .-. :
|  |  |  || '-' '       |  |   \   --. \    / \   --.|  |   .-'  `)\   --.
`--`--`--'|  |-'        `--'    `----'  `--'   `----'`--'   `----'  `----'
          `--'
    ";
        println!("{}", banner.green());
    }

    pub fn args(&mut self, args: Vec<String>) -> &mut Self {
        self.args = args[1..].to_owned();
        self
    }

    pub fn params(&mut self, item: Param<'a>) -> &mut Self {
        self.params.push(item);
        self
    }

    fn options(&self) {
        println!("{}", "参数：".red());
        self.params.iter().for_each(|item| item.to_string());
    }

    fn usage(&self) {
        println!("{}", "用法：".red());
        println!("\t{}", "mp-reverse [参数] [子命令]".blue())
    }


    fn match_one_param(&self, data: &str) {
        match data {
            "-V" | "--version" => {
                self.version();
            },
            "-H" | "--help" => {
                self.help();
            },
            _ => {
                println!("{}", "参数缺失，请执行'mp-reverse --help'，参看使用文档".red());
            }
        };
    }

    fn match_many_param(&self, arr: Vec<String>) -> Option<(String, String, String)> {
        let mut x: Vec<Param> = self.params.clone().into_iter().filter(|node| !node.is_interrupt).collect();

        for mut i in 0..arr.len() {
            x.iter_mut().for_each(|item| {
                if arr[i].eq(item.get_short_name().as_str()) || arr[i].eq(item.get_param_name().as_str()) {
                    item.is_match = true;
                    i += 1;
                    item.param_value = arr[i].as_str();
                }
            });
        }

        let config_path = if x[0].param_value.eq("") { x[0].default_value } else { x[0].param_value };
        let file_path = if x[1].param_value.eq("") { x[1].default_value } else { x[1].param_value };
        let author = if x[2].param_value.eq("") { x[2].default_value } else { x[2].param_value };
        Some((config_path.to_string(), file_path.to_string(), author.to_string()))
    }

    pub fn parse_match(&self) -> Option<(String, String, String)> {
        self.banner();
        if self.args.len() <= 0 {
            println!("{}", "参数缺失，请执行'mp-reverse --help'，参看使用文档".red());
            None
        } else if self.args.len() == 1 {
            self.match_one_param(self.args[0].as_str());
            None
        } else {
            self.match_many_param(self.args.clone())
        }
    }

    fn version(&self) {
        println!("mp-reverse v1.0.0")
    }

    fn help(&self) {
        self.usage();
        self.options();
    }



}

#[derive(Debug, Clone)]
pub struct Param<'a> {
    // 短参数
    short_name: &'a str,
    // 完整参数
    param_name: &'a str,
    // 描述
    describe: &'a str,
    // 默认值
    default_value: &'a str,
    // 是否匹配
    is_match: bool,
    // 参数值
    param_value: &'a str,
    // 是否中断后面参数
    is_interrupt: bool,
    // 必填
    is_required: bool,

}

impl<'a> Param<'a> {

    fn new() -> Self {
        Param {
            short_name: "",
            param_name: "",
            describe: "",
            default_value: "",
            is_match: false,
            param_value: "",
            is_interrupt: false,
            is_required: true,
        }
    }

    fn short_name(&mut self, name: &'a str) -> &mut Self {
        self.short_name = name;
        self
    }

    fn get_short_name(&self) -> String {
        format!("-{}", self.short_name)
    }

    fn param_name(&mut self, name: &'a str) -> &mut Self {
        self.param_name = name;
        self
    }

    fn get_param_name(&self) -> String {
        format!("--{}", self.param_name)
    }

    fn describe(&mut self, desc: &'a str) -> &mut Self {
        self.describe = desc;
        self
    }

    fn default_value(&mut self, value: &'a str) -> &mut Self {
        self.default_value = value;
        self
    }

    fn is_match(&mut self, value: bool) -> &mut Self {
        self.is_match = value;
        self
    }

    fn param_value(&mut self, value: &'a str) -> &mut Self {
        self.param_value = value;
        self
    }

    fn is_interrupt(&mut self, value: bool) -> &mut Self {
        self.is_interrupt = value;
        self
    }

    fn is_required(&mut self, value: bool) -> &mut Self {
        self.is_required = value;
        self
    }

    fn to_string(&self) {
        let result = if self.default_value.eq("") {
            format!(
                "\t{param:<width$}{desc}",
                param=format!("-{},--{}", self.short_name, self.param_name),
                desc=self.describe,
                width=50
            )
        } else {
            format!("\t{param:<width$}{value:<value_width$}{desc}",
                     param=format!("-{},--{}", self.short_name, self.param_name),
                     desc=self.describe,
                     value=self.default_value,
                     width=20,
                     value_width=30
            )
        };
        println!("{}", result.blue())
    }

}



#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test() {
        let mut param = Param::new();
        param.short_name("f")
            .param_name("config")
            .describe("配置文件")
            .default_value("default.json");
        println!("{:?}", param)
    }

    #[test]
    fn test1() {
        let flag = Flag::new(vec![
            "".to_string(),
            "-a".to_string(),
            "molong".to_string(),
            "-f".to_string(),
            "db.json".to_string(),
        ]);
        // flag.args(vec!["".to_string(), "--version".to_string()]);
        let option = flag.parse_match();
        println!("{:?}", option);
    }

}